home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / fileutil.zip / CHMOD.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  10KB  |  400 lines

  1. /* chmod -- change permission modes of files
  2.    Copyright (C) 1989, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  19.    This port is also distributed under the terms of the
  20.    GNU General Public License as published by the
  21.    Free Software Foundation.
  22.  
  23.    Please note that this file is not identical to the
  24.    original GNU release, you should have received this
  25.    code as patch to the official release.  */
  26.  
  27. #ifdef MSDOS
  28. static char RCS_Id[] =
  29.   "$Header: e:/gnu/fileutil/RCS/chmod.c 1.4.0.2 90/09/19 11:17:44 tho Exp $";
  30.  
  31. static char Program_Id[] = "chmod";
  32. static char RCS_Revision[] = "$Revision: 1.4.0.2 $";
  33.  
  34. #define VERSION \
  35.   "GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
  36.   (sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
  37.  
  38. #define COPYING \
  39.   "This is free software, distributed under the terms of the\n" \
  40.   "GNU General Public License.  For details, see the file COPYING.\n"
  41. #endif /* MSDOS */
  42.  
  43. /* Usage: chmod [-Rcdfv] mode file...
  44.           mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number.
  45.  
  46.    Options:
  47.    -R    Recursively change modes of directory contents.
  48.    -c    Verbosely describe only files whose modes actually change.
  49.    -d    Dereference symbolic links (recursively change the modes of
  50.     directories pointed to by symbolic links).
  51.    -f    Do not print error messages about files.
  52.    -v    Verbosely describe changed modes.
  53.  
  54.    David MacKenzie <djm@ai.mit.edu> */
  55.  
  56. #include <stdio.h>
  57. #include <getopt.h>
  58. #include <sys/types.h>
  59. #include "modechange.h"
  60. #include "system.h"
  61.  
  62. #ifdef STDC_HEADERS
  63. #include <errno.h>
  64. #include <stdlib.h>
  65. #else
  66. char *malloc ();
  67. char *realloc ();
  68.  
  69. extern int errno;
  70. #endif
  71.  
  72. #ifdef MSDOS
  73.  
  74. #include <malloc.h>
  75. #include <io.h>
  76.  
  77. #define lstat stat
  78.  
  79. extern void main (int argc, char **argv);
  80. extern void filemodestring (struct stat *,char *);
  81. extern void error (int status, int errnum, char *message, ...);
  82. extern void mode_string (unsigned short mode, char *str);
  83.  
  84. static int change_file_mode (char *file, struct mode_change *changes);
  85. static int change_dir_mode (char *dir, struct mode_change *changes,\
  86.                 struct stat *statp);
  87. extern char *savedir (char *dir, unsigned name_size);
  88. static char *stpcpy (char *dest, char *source);
  89. static void describe_change (char *file, unsigned short mode, int changed);
  90. static char *xmalloc (unsigned int n);
  91. static char *xrealloc (char *p, unsigned n);
  92. static char *stp_cpy (char *dest, char *source);
  93. static void usage (void);
  94.  
  95. #else /* not MSDOS */
  96.  
  97. int lstat ();
  98. int stat ();
  99.  
  100. char *savedir ();
  101. char *xmalloc ();
  102. char *xrealloc ();
  103. int change_file_mode ();
  104. int change_dir_mode ();
  105. void describe_change ();
  106. void error ();
  107. void mode_string ();
  108. void usage ();
  109.  
  110. #endif /* not MSDOS */
  111.  
  112. typedef enum
  113. {
  114.   false = 0, true = 1
  115. } boolean;
  116.  
  117. /* The name the program was run with. */
  118. char *program_name;
  119.  
  120. /* If true, change the modes of directories recursively. */
  121. boolean recurse;
  122.  
  123. /* If true, force silence (no error messages). */
  124. boolean force_silent;
  125.  
  126. /* If true, describe the modes we set. */
  127. boolean verbose;
  128.  
  129. /* If true, describe only modes that change. */
  130. boolean changes_only;
  131.  
  132. /* A pointer to either lstat or stat. */
  133. #ifdef MSDOS
  134. int (*xstat) (char *, struct stat *);
  135. #else
  136. int (*xstat) ();
  137. #endif
  138.  
  139. /* Parse the ASCII mode given on the command line into a linked list
  140.    of `struce mode_change' and apply that to each file argument. */
  141.  
  142. void
  143. main (argc, argv)
  144.      int argc;
  145.      char **argv;
  146. {
  147.   extern int optind;
  148.   struct mode_change *changes;
  149.   int errors = 0;
  150.   int modeind = 0;        /* Index of the mode argument in `argv'. */
  151.   int thisind;
  152.   int c;
  153.  
  154.   program_name = argv[0];
  155.   recurse = force_silent = verbose = changes_only = false;
  156.   xstat = lstat;
  157.  
  158.   while (1)
  159.     {
  160.       thisind = optind ? optind : 1;
  161.  
  162. #ifdef MSDOS
  163.       c = getopt (argc, argv, "RcdfvrwxXstugoa,+-=CV");
  164. #else
  165.       c = getopt (argc, argv, "RcdfvrwxXstugoa,+-=");
  166. #endif
  167.       if (c == EOF)
  168.     break;
  169.  
  170.       switch (c)
  171.     {
  172.     case 'r':
  173.     case 'w':
  174.     case 'x':
  175.     case 'X':
  176.     case 's':
  177.     case 't':
  178.     case 'u':
  179.     case 'g':
  180.     case 'o':
  181.     case 'a':
  182.     case ',':
  183.     case '+':
  184.     case '-':
  185.     case '=':
  186.       if (modeind != 0 && modeind != thisind)
  187.         error (1, 0, "invalid mode");
  188.       modeind = thisind;
  189.       break;
  190.     case 'R':
  191.       recurse = true;
  192.       break;
  193.     case 'c':
  194.       verbose = true;
  195.       changes_only = true;
  196.       break;
  197.     case 'd':
  198.       xstat = stat;
  199.       break;
  200.     case 'f':
  201.       force_silent = true;
  202.       break;
  203.     case 'v':
  204.       verbose = true;
  205.       break;
  206. #ifdef MSDOS
  207.     case 'C':
  208.       fprintf (stderr, COPYING);
  209.       exit (0);
  210.       break;
  211.     case 'V':
  212.       fprintf (stderr, VERSION);
  213.       exit (0);
  214.       break;
  215. #endif
  216.     default:
  217.       usage ();
  218.     }
  219.     }
  220.  
  221.   if (modeind == 0)
  222.     modeind = optind++;
  223.   if (optind >= argc)
  224.     usage ();
  225.  
  226.   changes = mode_compile (argv[modeind],
  227.               MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS);
  228.   if (changes == MODE_INVALID)
  229.     error (1, 0, "invalid mode");
  230.   else if (changes == MODE_MEMORY_EXHAUSTED)
  231.     error (1, 0, "virtual memory exhausted");
  232.  
  233.   for (; optind < argc; ++optind)
  234.     errors |= change_file_mode (argv[optind], changes);
  235.  
  236.   exit (errors);
  237. }
  238.  
  239. /* Change the mode of `file' according to the list of operations `changes'.
  240.    Return 0 if successful, 1 if errors occurred. */
  241.  
  242. int
  243. change_file_mode (file, changes)
  244.      char *file;
  245.      struct mode_change *changes;
  246. {
  247.   struct stat file_stats;
  248.   unsigned short newmode;
  249.   int errors = 0;
  250.  
  251.   if ((*xstat) (file, &file_stats))
  252.     {
  253.       if (force_silent == false)
  254.     error (0, errno, "%s", file);
  255.       return 1;
  256.     }
  257. #ifdef S_IFLNK
  258.   if ((file_stats.st_mode & S_IFMT) == S_IFLNK)
  259.     return 0;
  260. #endif
  261.  
  262.   newmode = mode_adjust (file_stats.st_mode, changes);
  263.  
  264.   if (newmode != (file_stats.st_mode & 07777))
  265.     {
  266.       if (verbose)
  267.     describe_change (file, newmode, 1);
  268.       if (chmod (file, (int) newmode))
  269.     {
  270.       if (force_silent == false)
  271.         error (0, errno, "%s", file);
  272.       errors = 1;
  273.     }
  274.     }
  275.   else if (verbose && changes_only == false)
  276.     describe_change (file, newmode, 0);
  277.  
  278.   if (recurse && (file_stats.st_mode & S_IFMT) == S_IFDIR)
  279.     errors |= change_dir_mode (file, changes, &file_stats);
  280.   return errors;
  281. }
  282.  
  283. /* Recursively change the modes of the files in directory `dir'
  284.    according to the list of operations `changes'.
  285.    `statp' points to the results of lstat or stat on `dir'.
  286.    Return 0 if successful, 1 if errors occurred. */
  287.  
  288. int
  289. change_dir_mode (dir, changes, statp)
  290.      char *dir;
  291.      struct mode_change *changes;
  292.      struct stat *statp;
  293. {
  294.   char *name_space, *namep;
  295.   char *path;            /* Full path of each entry to process. */
  296.   unsigned dirlength;        /* Length of `dir' and '\0'. */
  297.   unsigned filelength;        /* Length of each pathname to process. */
  298.   unsigned pathlength;        /* Bytes allocated for `path'. */
  299.   int errors = 0;
  300.  
  301.   errno = 0;
  302.   name_space = savedir (dir, statp->st_size);
  303.   if (name_space == NULL)
  304.     {
  305.       if (errno)
  306.     {
  307.       if (force_silent == false)
  308.         error (0, errno, "%s", dir);
  309.       return 1;
  310.     }
  311.       else
  312.     error (1, 0, "virtual memory exhausted");
  313.     }
  314.  
  315.   dirlength = strlen (dir) + 1;    /* + 1 is for the trailing '/'. */
  316.   pathlength = dirlength + 1;
  317.   /* Give `path' a dummy value; it will be reallocated before first use. */
  318.   path = xmalloc (pathlength);
  319.   strcpy (path, dir);
  320.   path[dirlength - 1] = '/';
  321.  
  322.   for (namep = name_space; *namep; namep += filelength - dirlength)
  323.     {
  324.       filelength = dirlength + strlen (namep) + 1;
  325.       if (filelength > pathlength)
  326.     {
  327.       pathlength = filelength * 2;
  328.       path = xrealloc (path, pathlength);
  329.     }
  330.       strcpy (path + dirlength, namep);
  331.       errors |= change_file_mode (path, changes);
  332.     }
  333.   free (path);
  334.   free (name_space);
  335.   return errors;
  336. }
  337.  
  338. /* Tell the user the mode `mode' that file `file' has been set to;
  339.    if `changed' is zero, `file' had that mode already. */
  340.  
  341. void
  342. describe_change (file, mode, changed)
  343.      char *file;
  344.      unsigned short mode;
  345.      int changed;
  346. {
  347.   char perms[11];        /* "-rwxrwxrwx" ls-style modes. */
  348.  
  349.   mode_string (mode, perms);
  350.   perms[10] = '\0';        /* `mode_string' does not null terminate. */
  351.   if (changed)
  352.     printf ("mode of %s changed to %04o (%s)\n",
  353.         file, mode & 07777, &perms[1]);
  354.   else
  355.     printf ("mode of %s retained as %04o (%s)\n",
  356.         file, mode & 07777, &perms[1]);
  357. }
  358.  
  359. /* Allocate `n' bytes of memory dynamically, with error checking.  */
  360.  
  361. char *
  362. xmalloc (n)
  363.      unsigned n;
  364. {
  365.   char *p;
  366.  
  367.   p = malloc (n);
  368.   if (p == 0)
  369.     error (1, 0, "virtual memory exhausted");
  370.   return p;
  371. }
  372.  
  373. char *
  374. xrealloc (p, n)
  375.      char *p;
  376.      unsigned n;
  377. {
  378.   p = realloc (p, n);
  379.   if (p == 0)
  380.     error (1, 0, "virtual memory exhausted");
  381.   return p;
  382. }
  383.  
  384. void
  385. usage ()
  386. {
  387. #ifdef MSDOS
  388.   fprintf (stderr, "\
  389. Usage: %s [-RcdfvCV] mode file...\n\
  390.        mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number\n",
  391.        program_name);
  392. #else /* not MSDOS */
  393.   fprintf (stderr, "\
  394. Usage: %s [-Rcdfv] mode file...\n\
  395.        mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number\n",
  396.        program_name);
  397. #endif /* not MSDOS */
  398.   exit (1);
  399. }
  400.